package com.jubaozan.c3.framework.logs.logback;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.encoder.EncoderBase;
import com.jubaozan.c3.framework.logs.UtilElk;
import com.jubaozan.c3.framework.logs.UtilJson;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

import static com.jubaozan.c3.framework.logs.model.ElkEventKey.*;


import lombok.extern.slf4j.Slf4j;

/**
 * @author jiangjinwu
 * @version 1.0
 * @since 2025/10/7 18:06
 */

@Slf4j

public class ElkEncoder extends EncoderBase<ILoggingEvent> {
  private static final byte[] EMPTY_BYTES = new byte[0];
  private static final int minBufferSize = 2048;

  @Override
  public byte[] headerBytes() {
    return EMPTY_BYTES;
  }

  @Override
  public byte[] footerBytes() {
    return EMPTY_BYTES;
  }

  @Override
  public byte[] encode(ILoggingEvent event) {
    try (ByteArrayOutputStream out = new ByteArrayOutputStream(minBufferSize)) {
      Map<String, Object> map = toMap(event);
      UtilJson.writeEvent(out, map);
      out.write(UtilElk.LINESEPARATOR_BYTES);
      return out.toByteArray();
    } catch (IOException e) {
      addWarn("Error encountered while encoding log event. Event: " + event, e);
      return EMPTY_BYTES;
    }
  }

  /**
   * @return <a href="https://logging.apache.org/log4j/2.x/manual/layouts.html#JSONLayout">log4j2 JSONLayout</a>
   */
  private Map<String, Object> toMap(ILoggingEvent event) {
    Map<String, Object> ret = new LinkedHashMap<>();
    ret.put(APP_ID, UtilLogback.getAppId(event));
    ret.put(HOST_IP, UtilElk.HOST_IP);
    ret.put(PID, UtilElk.JVM_PID);

    ret.put(TIMESTAMP, UtilElk.formatDate(event.getTimeStamp()));
    ret.put(THREAD, event.getThreadName());
    ret.put(LEVEL, UtilElk.toStr(event.getLevel()));
    ret.put(LOGGER_NAME, event.getLoggerName());
    ret.put(MARKER, UtilLogback.toMap(event.getMarker()));

    String message = event.getFormattedMessage();
    ret.put(MESSAGE, message == null ? UtilElk.MESSAGE_NULL_VAL : message);

    Map<String, String> mdcMap = event.getMDCPropertyMap();
    if (UtilElk.notEmpty(mdcMap)) ret.put(CONTEXT_MAP, mdcMap);

    ret.put(SOURCE, UtilElk.getSource(event.getCallerData()));
    ret.put(THROWN, UtilLogback.toMap(event.getThrowableProxy()));
    return ret;
  }

}
